namespace FIREFLYX {
    /** 凹凸 + 镜面高光 着色器*/
    export const BUILTIN_SHADER_BUMPED_SPECULAR = `BumpedSpecular`;
    DefaultAsset.shaderGenMap[BUILTIN_SHADER_BUMPED_SPECULAR] = () => {

        //code 0 计算 级联阴影
        const vsCode0 = `#version 300 es
        precision mediump float;
        layout (location = 0) in vec4 a_Position; //顶点 位置 是有默认值的 (0,0,0,1)
        layout (location = 3) in vec2 a_UV;       //UV 纹理坐标
        layout (location = 1) in vec3 a_Normal;   //法线 向量
        uniform ubo_model_block{
            mat4 u_mMtx;                //模型矩阵
        } uboModel;
        uniform ubo_cam_block{
            mat4 u_viewMtx;             //视窗矩阵
            mat4 u_projectMtx;          //投影矩阵
            vec4 u_eyePos;              //眼睛位置
        } uboCam;

        uniform mat4 u_lightVPMatrix_0;   //转到 主光源VP空间矩阵
        uniform mat4 u_lightVPMatrix_1;   //转到 主光源VP空间矩阵
        uniform mat4 u_lightVPMatrix_2;   //转到 主光源VP空间矩阵
        uniform mat4 u_lightVPMatrix_3;   //转到 主光源VP空间矩阵
        uniform vec4 u_csm_split;

        out vec3 v_wPos;
        out vec2 v_uv;
        out vec3 v_wNormal;
        out vec4[4] v_wPosLightSpaces;
        out float v_zDLin;  //0-1 范围z 的距离值
        void main() {
            v_uv = a_UV;
            v_wNormal = mat3(transpose(inverse(uboModel.u_mMtx))) * a_Normal;    //逆转置矩阵,可以让法向量在非统一缩放后保持准确,不受干扰。
            vec4 mPos = vec4(a_Position.xyz,1.0);
            v_wPos = (uboModel.u_mMtx * mPos).xyz;
            // mat4 mvpMat = u_projectMtx * u_viewMtx * uboModel.u_mMtx;
            mat4 mvpMat = uboCam.u_projectMtx * uboCam.u_viewMtx * uboModel.u_mMtx;
            gl_Position = mvpMat * a_Position;
            vec4 wPosV4 = vec4(v_wPos.xyz, 1.0);
            vec4 vPos = uboCam.u_viewMtx * wPosV4;
            float shadowDistance = u_csm_split[3];
            v_zDLin = vPos.z / shadowDistance;                                  //范围映射到  0-1
            v_wPosLightSpaces[0] = u_lightVPMatrix_0 * wPosV4;
            v_wPosLightSpaces[1] = u_lightVPMatrix_1 * wPosV4;
            v_wPosLightSpaces[2] = u_lightVPMatrix_2 * wPosV4;
            v_wPosLightSpaces[3] = u_lightVPMatrix_3 * wPosV4;
        }
        `;

        const fsCode0 = `#version 300 es
        precision mediump float;
        uniform sampler2D u_mainTex;
        uniform sampler2D u_mainShadowMap_0;
        uniform sampler2D u_mainShadowMap_1;
        uniform sampler2D u_mainShadowMap_2;
        uniform sampler2D u_mainShadowMap_3;
        uniform vec4 u_csm_split;
        uniform vec4 u_mainColor;       //主颜色 颜色

        uniform ubo_cam_block{
            mat4 u_viewMtx;                 //视窗矩阵
            mat4 u_projectMtx;              //投影矩阵
            vec4 u_eyePos;                  //眼睛位置
        } uboCam;

        uniform ubo_light_block{
            uniform vec4 _mainLightDir;
            uniform vec4 _mainLightColor;
            uniform vec4[64] _addLightsPos;
            uniform vec4[64] _addLightsColor;
            uniform vec4[64] _addLightsAtt;
            uniform vec4[64] _addLightsSpotDir;
        } uboLight;
        
        uniform ubo_material_block{
            uniform float u_spotSpec;       //镜面反射光斑
        } uboMaterial;

        in vec3 v_wPos;
        in vec2 v_uv;
        in vec3 v_wNormal;
        in vec4[4] v_wPosLightSpaces;
        in float v_zDLin;
        out vec4 color;

        float ShadowCalculation(vec4 wPosLightSpace , sampler2D shadowMap , float NoL)
        {
            // 执行透视除法
            vec3 projCoords = wPosLightSpace.xyz / wPosLightSpace.w;
            // 变换到[0,1]的范围
            projCoords = projCoords * 0.5 + 0.5;
            // 取得当前片段在光源视角下的深度
            float currentDepth = projCoords.z;
            //调节 阴影失真(Shadow Acne) 问题使用 阴影偏移
            float baseBias = 0.01;
            // float bias = max(baseBias * (1.0 - NoL), baseBias * 0.1);  //自适应处理
            float bias = baseBias; 
            
            bool isPCF = true;
            
            float shadow = 0.0;
            if(!isPCF){
                // 取得最近点的深度(使用[0,1]范围下的wPosLightSpace当坐标)
                float closestDepth = texture(shadowMap, projCoords.xy).r;
                // 检查当前片段是否在阴影中
                shadow = step(closestDepth , currentDepth - bias);
            }else{
                vec2 texelSize = 1.0 / vec2(textureSize(shadowMap, 0));
                for(int x = -1; x <= 1; ++x)
                {
                    for(int y = -1; y <= 1; ++y)
                    {
                        float pcfDepth = texture(shadowMap, projCoords.xy + vec2(x, y) * texelSize).r; 
                        //shadow += currentDepth - bias > pcfDepth ? 1.0 : 0.0;        
                        shadow += step(pcfDepth , currentDepth - bias);       
                    }    
                }
                shadow /= 9.0;
            }

            //超出 置 0处理 ,解决黑影错误问题
            float shadowMapBoundary = 1.0;
            // shadowMapBoundary = step(currentDepth , 1.0);
            shadowMapBoundary *= step(projCoords.x , 1.0);
            shadowMapBoundary *= step(0.0 , projCoords.x);
            shadowMapBoundary *= step(projCoords.y , 1.0);
            shadowMapBoundary *= step(0.0 , projCoords.y);

            return shadow * shadowMapBoundary;
        }

        void main(){
            vec4 texColor = texture(u_mainTex , v_uv) * u_mainColor;          //纹理颜色

            vec3 L = uboLight._mainLightDir.xyz * -1.0;         //L  指向光源的方向
            vec3 N = normalize(v_wNormal);                      //N  世界法向量(normalize 是必须的,因为片元上的wNormal是差值得到,长度不一定等于1了)
            vec3 V = normalize(uboCam.u_eyePos.xyz - v_wPos.xyz);       //V  指向相机
            vec3 H = normalize(V + L);                          //H  半角向量
            float NoL = dot(N,L);

            //shadow 
            float shadow0 = ShadowCalculation(v_wPosLightSpaces[0] , u_mainShadowMap_0 , NoL);
            float shadow1 = ShadowCalculation(v_wPosLightSpaces[1] , u_mainShadowMap_1 , NoL);
            float shadow2 = ShadowCalculation(v_wPosLightSpaces[2] , u_mainShadowMap_2 , NoL);
            float shadow3 = ShadowCalculation(v_wPosLightSpaces[3] , u_mainShadowMap_3 , NoL);
            float csmSpVal0 = step(0.0 , v_zDLin) * step(v_zDLin , u_csm_split[0]);
            float csmSpVal1 = step(u_csm_split[0] , v_zDLin) * step(v_zDLin , u_csm_split[1]);
            float csmSpVal2 = step(u_csm_split[1] , v_zDLin) * step(v_zDLin , u_csm_split[2]);
            float csmSpVal3 = step(u_csm_split[2] , v_zDLin) * step(v_zDLin , 1.0);
            shadow0 *= csmSpVal0;
            shadow1 *= csmSpVal1;
            shadow2 *= csmSpVal2;
            shadow3 *= csmSpVal3;
            float shadow = shadow0 + shadow1 + shadow2 + shadow3;
            float shadowAtten = 1.0 - shadow;
            vec4 CSMDebugColor = vec4(csmSpVal0 , csmSpVal1 , csmSpVal2 , csmSpVal3);

            //直接光照
            float diffuse = NoL;                                                                //diffuse (漫反射)
            float spec = pow(max(0.0, dot(H , N)) , max(0.01 , uboMaterial.u_spotSpec));        //spec (镜面反射)
            vec3 dirDiffColor = uboLight._mainLightColor.rgb * texColor.xyz * diffuse * shadowAtten;
            vec3 dirSpecColor = uboLight._mainLightColor.rgb * spec * shadowAtten;

            // color = vec4(shadow,0.0,0.0,1.0);
            //color = vec4(1.0,0.0,0.0,1.0);
            //color = vec4(v_uv.x,v_uv.y,0.0,1.0);
            //color = texColor;
            //color = vec4(v_wPos , 1.0);
            //color = vec4(uboLight._mainLightColor , 1.0);
            //color = vec4(uboCam.u_eyePos.xyz , 1.0);
            //color = vec4(L , 1.0);
            //color = vec4(N , 1.0);
            //color = vec4(diffuse,diffuse,diffuse , 1.0);
            //color = vec4(spec,spec,spec , 1.0);
            //color = vec4(dirDiffColor , 1.0);
            //color = vec4(dirSpecColor , 1.0);
            color = vec4(dirDiffColor + dirSpecColor , max (texColor.a , spec * shadowAtten));

            //CSM Debug
            color += CSMDebugColor * 0.2;
         }
        `;

        //使用 屏幕空间阴影图计算阴影
        const vsCode1 = `#version 300 es
        precision mediump float;
        layout (location = 0) in vec4 a_Position;   //顶点 位置 是有默认值的 (0,0,0,1)
        layout (location = 3) in vec2 a_UV;         //UV 纹理坐标
        layout (location = 1) in vec3 a_Normal;     //法线 向量
        uniform ubo_model_block{
            mat4 u_mMtx;                            //模型矩阵
        } uboModel;
        uniform ubo_cam_block{
            mat4 u_viewMtx;                         //视窗矩阵
            mat4 u_projectMtx;                      //投影矩阵
            vec4 u_eyePos;                          //眼睛位置
        } uboCam;

        out vec3 v_wPos;
        out vec2 v_uv;
        out vec3 v_wNormal;
        void main() {
            v_uv = a_UV;
            v_wNormal = mat3(transpose(inverse(uboModel.u_mMtx))) * a_Normal;    //逆转置矩阵,可以让法向量在非统一缩放后保持准确,不受干扰。
            vec4 mPos = vec4(a_Position.xyz,1.0);
            v_wPos = (uboModel.u_mMtx * mPos).xyz;
            // mat4 mvpMat = u_projectMtx * u_viewMtx * uboModel.u_mMtx;
            mat4 mvpMat = uboCam.u_projectMtx * uboCam.u_viewMtx * uboModel.u_mMtx;
            gl_Position = mvpMat * a_Position;
        }
        `;

        const fsCode1 = `#version 300 es
        precision mediump float;
        uniform sampler2D u_mainTex;
        uniform vec4 u_mainColor;           //主颜色 颜色

        uniform ubo_cam_block{
            mat4 u_viewMtx;                     //视窗矩阵
            mat4 u_projectMtx;                  //投影矩阵
            vec4 u_eyePos;                      //眼睛位置
        } uboCam;

        uniform ubo_light_block{
            uniform vec4 _mainLightDir;
            uniform vec4 _mainLightColor;
            uniform vec4[64] _addLightsPos;
            uniform vec4[64] _addLightsColor;
            uniform vec4[64] _addLightsAtt;
            uniform vec4[64] _addLightsSpotDir;
        } uboLight;
        
        uniform ubo_material_block{
            uniform float u_spotSpec;           //镜面反射光斑
        } uboMaterial;

        uniform sampler2D u_screenShadowTex;    //屏幕空间阴影纹理
        uniform vec2 u_resolution;              //画布分辨率

        in vec3 v_wPos;
        in vec2 v_uv;
        in vec3 v_wNormal;
        out vec4 color;

        void main(){
            vec2 screenUV = vec2(gl_FragCoord.x / u_resolution.x , gl_FragCoord.y / u_resolution.y);
            //shadow
            vec4 shadowMapColor = texture(u_screenShadowTex , screenUV);
            float shadowAtten = shadowMapColor.r;
            
            vec4 texColor = texture(u_mainTex , v_uv) * u_mainColor;                    //纹理颜色

            vec3 L = uboLight._mainLightDir.xyz * -1.0;                                             //L  指向光源的方向
            vec3 N = normalize(v_wNormal);                                                          //N  世界法向量(normalize 是必须的,因为片元上的wNormal是差值得到,长度不一定等于1了)
            vec3 V = normalize(uboCam.u_eyePos.xyz - v_wPos.xyz);                                   //V  指向相机
            vec3 H = normalize(V + L);                                                              //H  半角向量
            float NoL = clamp (dot(N,L) , 0. , 1.);


            //直接光照
            float diffuse = NoL;                                                                                              //diffuse (漫反射)
            float spec = pow(max(0.0, dot(H , N)) , max(0.01 , uboMaterial.u_spotSpec)) * step(0.0 , NoL);            //spec (镜面反射) 乘 step(0.0 , NoL) 保证受光面半球才有高光 
            vec3 dirDiffColor = uboLight._mainLightColor.rgb * texColor.xyz * diffuse * shadowAtten;
            vec3 dirSpecColor = uboLight._mainLightColor.rgb * spec * shadowAtten;

            // color = vec4(shadow,0.0,0.0,1.0);
            //color = vec4(1.0,0.0,0.0,1.0);
            //color = vec4(v_uv.x,v_uv.y,0.0,1.0);
            //color = texColor;
            //color = vec4(v_wPos , 1.0);
            //color = vec4(uboLight._mainLightColor , 1.0);
            //color = vec4(uboCam.u_eyePos.xyz , 1.0);
            //color = vec4(L , 1.0);
            // color = vec4(N , 1.0);

            // color = vec4(H * NoL, 1.0);
            // color = vec4(V, 1.0);

            //color = vec4(diffuse,diffuse,diffuse , 1.0);
            //color = vec4(spec,spec,spec , 1.0);
            //color = vec4(dirDiffColor , 1.0);
            //color = vec4(dirSpecColor , 1.0);
            color = vec4(dirDiffColor + dirSpecColor , max (texColor.a , spec * shadowAtten));

         }
        `;

        //
        vsCode0;
        fsCode0;

        //glsl
        const vs = new GLSL();
        vs.setCode(vsCode1);
        const fs = new GLSL();
        fs.setCode(fsCode1);

        //shader
        let result: Shader = new Shader();
        result.tag = BUILTIN_SHADER_BUMPED_SPECULAR;
        result.lightMode = RenderPipeline.LM_FORWARD;
        result.vertexGLSL = vs;
        result.fragmentGLSL = fs;
        //unifrom 默认值
        result.definePropertyMap = {};
        //
        result.definePropertyMap.u_mainTex = {
            type: "texture",
            value: "White"
        };

        // result.definePropertyMap.u_mainColor = {
        //     type: "color",
        //     value: [1, 1, 1, 1]
        // };

        //block unifrom 属性
        result.definePropertyMap[`ubo_material_block.u_spotSpec`] = {
            type: "float",
            value: 100
        };

        result.definePropertyMap[`u_mainColor`] = {
            type: "color",
            value: [1, 1, 1, 1]
        };

        // result.definePropertyMap[`ubo_light_block.u_lightColor`] = {
        //     type: "color",
        //     value: [1, 1, 1, 1]
        // };

        // result.definePropertyMap[`ubo_light_block.u_lightDir`] = {
        //     type: "float",
        //     value: [0, 0, 0]
        // };

        //apply
        result.apply();

        return result;
    };
}